package db

import (
	"gorm.io/driver/mysql"
	"sync"
	"time"

	"gin-skeleton/etc"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

const (
	MysqlDrive = "mysql"
	MongodbDrive = "mongodb"
)

var (
	instance dbIns
	config *etc.Config
	once = &sync.Once{}
)

type dbIns map[string]map[string]*gorm.DB

// InitDbConnect 初始化数据库连接
func InitDbConnect(onlyDbName ...string) {
	once.Do(func() {
		config = etc.Load()
		if !isEnable() {
			logrus.Warnln("Db disabled")
			return
		}
		connection(onlyDbName...)
	})
}

// Mysql 获取连接实例
func Mysql(name string) *gorm.DB {
	return instance[MysqlDrive][name]
}
// Mongodb 获取连接实例
func Mongodb(name string) *gorm.DB{
	return instance[MongodbDrive][name]
}

func isEnable() bool {
	return config.Db.Enable
}

// Connection 数据库连接
func connection(onlyDbName ...string) {
	onlyDbNameMap := make(map[string]struct{})
	instance := make(dbIns)
	if len(onlyDbName) > 0 {
		for _,name := range onlyDbName {
			onlyDbNameMap[name] = struct{}{}
		}
	}
	config := etc.Load().Db
	for _, c := range config.Connections {
		// 按需实例化
		if len(onlyDbNameMap) == 0 {
			if !c.Enable {
				continue
			}
		}else if _,ok := onlyDbNameMap[c.Name]; !ok {
			continue
		}

		switch c.Drive {
		case MysqlDrive:
			db, err := gorm.Open(mysql.New(mysql.Config{
				DSN:               c.DSN,
				DefaultStringSize: c.DefaultStringSize,
			}), &gorm.Config{
				NamingStrategy:                           config.Gorm.NamingStrategy,
				SkipDefaultTransaction:                   config.Gorm.SkipDefaultTransaction,
				DryRun:                                   config.Gorm.DryRun,
				PrepareStmt:                              config.Gorm.PrepareStmt,
				DisableNestedTransaction:                 config.Gorm.DisableNestedTransaction,
				AllowGlobalUpdate:                        config.Gorm.AllowGlobalUpdate,
				DisableAutomaticPing:                     config.Gorm.DisableAutomaticPing,
				DisableForeignKeyConstraintWhenMigrating: config.Gorm.DisableForeignKeyConstraintWhenMigrating,
			})
			if err != nil {
				logrus.Error("Mysql connect:", err)
				return
			}
			instance[MysqlDrive][c.Name] = dbSetPool(db)
			logrus.Info("Mysql name:",c.Name ," connected.")
		}
	}
}

// 设置连接池
func dbSetPool(db *gorm.DB) *gorm.DB{
	if db == nil {
		return nil
	}

	// DB连接池配置
	tx, _ := db.DB()
	// 设置到数据库的最大打开连接数
	tx.SetMaxOpenConns(etc.Configure.Db.Gorm.MaxOpenConns)
	// 设置空闲连接池中的最大连接数
	tx.SetMaxIdleConns(etc.Configure.Db.Gorm.MaxIdleConns)
	// 设置连接可以重用的最长时间
	tx.SetConnMaxLifetime(time.Hour)
	return db
}
